package com.github.byakkili.bim.core.support.util;

import cn.hutool.core.util.ReflectUtil;
import com.github.byakkili.bim.core.handler.command.CommandProcessor;
import io.netty.util.internal.TypeParameterMatcher;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.core.ResolvableType;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Guannian Li
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class CommandProcessorUtils {

    private static final Map<Class<? extends CommandProcessor>, Class<?>> CACHE = new ConcurrentHashMap<>();

    private static final Method FIND0_METHOD = ReflectUtil.getMethod(TypeParameterMatcher.class, "find0", Object.class, Class.class, String.class);

    public static <T> Class<T> getMsgClass(final CommandProcessor processor) {
        Class<? extends CommandProcessor> processorClass = processor.getClass();

        Class<?> msg0Class = CACHE.get(processorClass);
        if (msg0Class == null) {
            msg0Class = getMsg0Class(processorClass);
            if (msg0Class != null) {
                Class<?> prevClass = CACHE.putIfAbsent(processorClass, msg0Class);
                if (prevClass != null) {
                    msg0Class = prevClass;
                }
            }
        }
        @SuppressWarnings("unchecked")
        Class<T> msgClass = (Class<T>) msg0Class;
        return msgClass;
    }

    public static Class<?> getMsg0Class(final Class<? extends CommandProcessor> processorClass) {
        return ResolvableType.forClass(CommandProcessor.class, processorClass).resolveGeneric(0);
    }

    /**
     * @deprecated 废弃, 改用另一个方法
     */
    @Deprecated
    public static <T> Class<T> getMsg0Class(final CommandProcessor processor) {
        return ReflectUtil.invokeStatic(FIND0_METHOD, processor, CommandProcessor.class, "I");
    }
}
